#include "paintarea.h"

cv::Rect rectangle;
ImageAnnItem polyData;
cv::Point p0;
bool flag = false;

PaintArea::PaintArea(QWidget *parent, Status *p) :
    QLabel(parent)
{
    pStatus = p;
}

void PaintArea::mousePressEvent(QMouseEvent *event)
{
    if(pStatus == nullptr)
        return;
    cv::Point p;
    // 得到鼠标按下的位置相对于图片左上角的坐标
    p.x = event->x() - getStartImagePixel().x;
    p.y = event->y() - getStartImagePixel().y;
    p /= scale;
    // 左键按下的事件处理
    if(event->button() == Qt::LeftButton)
    {
        flag = true;
        lButtonDownEvent(p);
    }
}

void PaintArea::mouseMoveEvent(QMouseEvent *event)
{
    if(pStatus == nullptr)
        return;
    if(!flag)
        return;
    cv::Point p;
    // 计算真实坐标
    p.x = (event->x() - getStartImagePixel().x);
    p.y = (event->y() - getStartImagePixel().y);
    p /= scale;
    lButtonMoveEvent(p);
    update();
}

void PaintArea::mouseReleaseEvent(QMouseEvent *event)
{
    if (pStatus == nullptr)
        return;
    cv::Point p;
    // 计算点在图片中的真实坐标
    p.x = (event->x() - getStartImagePixel().x);
    p.y = (event->y() - getStartImagePixel().y);
    p /= scale;
    if(event->button() == Qt::MidButton)
    {
        mButtonUpEvent(p);
    }
    else if(event->button() == Qt::LeftButton)
    {
        flag = false;
        lButtonUpEvent(p);
    }
    else if(event->button() == Qt::RightButton)
    {
        rButtonUpEvent(p);
    }
    update();
}

void PaintArea::lButtonUpEvent(cv::Point p)
{
    Type t = pStatus->getNowSelection();
        if (t == Point_Type)
        {
            ImageAnnItem item;
            item.setAnnType(Point_Type);
            item.addPoint(p);
            ImageAnnEntry &tmp = pStatus->getNowImageAnn().getImageEntries()[pStatus->getIndex()];
            tmp.addItem(item);
            tmp.setItemCounts(tmp.getItemCounts() + 1);
            isSaved = false;
        }
        else if (t == Rectangle_Type)
        {
            if (p.x == rectangle.x || p.y == rectangle.y)
                return;
            else
            {
                rectangle.width = p.x - rectangle.x;
                rectangle.height = p.y - rectangle.y;
                if (rectangle.width < 0)
                {
                    rectangle.x = p.x;
                    rectangle.width *= -1;
                }
                if (rectangle.height < 0)
                {
                    rectangle.y = p.y;
                    rectangle.height *= -1;
                }
                ImageAnnItem item;
                item.setAnnType(Rectangle_Type);
                item.addPoint(cv::Point(rectangle.x, rectangle.y));
                item.addPoint(cv::Point(rectangle.x + rectangle.width, rectangle.y));
                item.addPoint(cv::Point(rectangle.x + rectangle.width, rectangle.y + rectangle.height));
                item.addPoint(cv::Point(rectangle.x, rectangle.y + rectangle.height));
                ImageAnnEntry &tmp = pStatus->getNowImageAnn().getImageEntries()[pStatus->getIndex()];
                tmp.addItem(item);
                tmp.setItemCounts(tmp.getItemCounts() + 1);
                isSaved = false;
            }
            polyData.clear();
        }
        else if (t == Polygon_Type)
        {
            // 临时将多边形的点存放在polyData中，并且保证不重复存储
            if (count(polyData.getPoints().begin(), polyData.getPoints().end(), p) == 0)
                polyData.addPoint(p0);
            if (count(polyData.getPoints().begin(), polyData.getPoints().end(), p) == 0)
                polyData.addPoint(p);
        }
}

// 鼠标移动事件响应
void PaintArea::lButtonMoveEvent(cv::Point p)
{
    Type t = pStatus->getNowSelection();

    if(t == Rectangle_Type)
    {
        // 将当前绘制的矩形也保存在polyData中(PS:懒得重新定义变量了)
        polyData.clear();
        polyData.setAnnType(Rectangle_Type);
        polyData.addPoint(rectangle.tl());
        polyData.addPoint(p);
    }
}

void PaintArea::lButtonDownEvent(cv::Point p)
{
    Type t = pStatus->getNowSelection();

    if (t == Rectangle_Type)
    {
        rectangle.x = p.x;
        rectangle.y = p.y;
    }
    else if (t == Polygon_Type)
    {
        p0.x = p.x;
        p0.y = p.y;
        polyData.setAnnType(Polygon_Type);
    }
}

void PaintArea::rButtonUpEvent(cv::Point curp)
{
    ImageAnnEntry &entry = pStatus->getNowImageAnn().getImageEntries()[pStatus->getIndex()];
    vector<ImageAnnItem> &imageItems = entry.getImageItems();
    for(auto itemIter = imageItems.begin(); itemIter != imageItems.end();)
    {
       if(itemIter->getAnnType() == Point_Type)
       {
           auto iter = findPoint(itemIter->getPoints(), curp);
           if(iter != (itemIter->getPoints()).end())
           {
               itemIter = imageItems.erase(itemIter);
               entry.setItemCounts(entry.getItemCounts() - 1);
               isSaved = false;
               return;
           }
           else
               itemIter++;
       }
       else if(itemIter->getAnnType() == Rectangle_Type || itemIter->getAnnType() == Polygon_Type)
       {
           if(cv::pointPolygonTest(itemIter->getPoints(), curp, false) >= 0)
           {
               itemIter = imageItems.erase(itemIter);
               entry.setItemCounts(entry.getItemCounts() - 1);
               isSaved = false;
               return;
           }
           else
               itemIter++;
       }
    }
    polyData.clear();
}

void PaintArea::mButtonUpEvent(cv::Point)
{
    ImageAnnEntry &tmp = pStatus->getNowImageAnn().getImageEntries()[pStatus->getIndex()];
    tmp.addItem(polyData);
    tmp.setItemCounts(tmp.getItemCounts() + 1);
    polyData.clear();
    isSaved = false;
}

vector<cv::Point>::iterator PaintArea::findPoint(vector<cv::Point> &points, cv::Point curP)
{
    vector<cv::Point>::iterator iter;
    for (iter = points.begin(); iter != points.end(); ++iter)
    {
        if (abs((*iter).x - curP.x) < NEIGHBOR && abs((*iter).y - curP.y) < NEIGHBOR)
            break;
    }

    return iter;
}

void PaintArea::paintEvent(QPaintEvent *event)
{
    if(pStatus != nullptr)
        showAnnotation(polyData);
    QLabel::paintEvent(event);
}

void PaintArea::showAnnotation(ImageAnnItem &polyData)
{
    AnnotationImage annImage = pStatus->getNowAnnImage();
    cv::Mat tmp = annImage.drawAnnInImage(polyData, pStatus->getIndex());
    cv::resize(tmp, tmp, cv::Size(scale * tmp.size().width, scale * tmp.size().height));
    img = cvMat2QImage(tmp);
    // 设置显示图片
    this->setPixmap(QPixmap::fromImage(img));
    cv::Point p;
    p.x = (this->width()-img.width())/2;
    p.y = (this->height()-img.height())/2;
    setStartImagePixel(p);
}
